using System;

namespace Decision_Tree
{
	//attribute threshholds
	public enum AT
	{
		//to 'score' agents on their decisions
		S_DIST_FROM_HERDER_GOOD = 10,
		S_DIST_FROM_HERDER_BAD = 11,
		S_DIST_FROM_GOAL_GOOD = 12,
		S_DIST_FROM_GOAL_BAD = 13,
		S_FOOD_GOOD = 14,
		S_FOOD_BAD = 15,
		
		//to classify state as bool's when making a decision
		THRESH_B_CLOSE_TO_GOAL = 1500,
		THRESH_B_CLOSE_TO_FOOD = 600,
		THRESH_B_CLOSE_TO_HERDER = 1000,
		THRESH_B_TIME_LEFT = 40,
		THRESH_B_HAS_FOOD = 90
	}
	
	/* Attribute and action Enums */
	public enum Attribute
	{
		bCloseToGoal,
   		bCloseToFood,
   		bCloseToHerder,
		bTimeLeft,
		bHasFood,
		DEFAULT
	}

	public enum Actions
	{
		MoveTowardsGoal,
   		MoveTowardsFood,
		EvadeHerder,
		Lost,
		DEFAULT
	}	
	
	public class Knowledge
	{
		public float distanceToGoal;
   		public float distanceToFood;
   		public float distanceToHerder;
		public float gameTimeLeft;
		public float foodLevel;
		
		/* agent construct with floats */
		public Knowledge(float distToGoal, float distToFood, float distToHerder, float gTimeLeft, float foodLev) 
		{
			this.distanceToGoal = distToGoal;
   			this.distanceToFood = distToFood;
   			this.distanceToHerder = distToHerder;
			this.gameTimeLeft = gTimeLeft;
			this.foodLevel = foodLev;
		}
		
		/* agent construct with bools */
		public Knowledge(bool bCloseToGoal, bool bCloseToFood, bool bCloseToHerder, bool bTimeLeft, bool bHasFood)
		{
			this.distanceToGoal = floatForAttributeAndBool(Attribute.bCloseToGoal,bCloseToGoal);
   			this.distanceToFood = floatForAttributeAndBool(Attribute.bCloseToFood,bCloseToFood);
   			this.distanceToHerder = floatForAttributeAndBool(Attribute.bCloseToHerder,bCloseToHerder);
			this.gameTimeLeft = floatForAttributeAndBool(Attribute.bTimeLeft,bTimeLeft);
			this.foodLevel = floatForAttributeAndBool(Attribute.bHasFood,bHasFood);
		}
		
		/* agent construct with defaults */
		public Knowledge()
		{
			distanceToGoal = 0;
   			distanceToFood = 0;
   			distanceToHerder = 0;
			gameTimeLeft = 0;
			foodLevel = 0;			
		}
		
		public void setKnowledge(float distToGoal, float distToFood, float distToHerder, float gTimeLeft, float foodLev) 
		{
			this.distanceToGoal = distToGoal;
   			this.distanceToFood = distToFood;
   			this.distanceToHerder = distToHerder;
			this.gameTimeLeft = gTimeLeft;
			this.foodLevel = foodLev;
		}
		
		//gives a float value for an attribute
		public float floatForAttributeAndBool(Attribute attrib, bool val)
		{
			if(attrib == Attribute.bCloseToGoal)
			{
				if(val)
					return (float)AT.THRESH_B_CLOSE_TO_GOAL+1;
				return (float)AT.THRESH_B_CLOSE_TO_GOAL-1;		
			}
			else if(attrib == Attribute.bCloseToFood)
			{
				if(val)
					return (float)AT.THRESH_B_CLOSE_TO_FOOD+1;
				return (float)AT.THRESH_B_CLOSE_TO_FOOD-1;		
			}
			else if(attrib == Attribute.bCloseToHerder)
			{
				if(val)
					return (float)AT.THRESH_B_CLOSE_TO_HERDER+1;
				return (float)AT.THRESH_B_CLOSE_TO_HERDER-1;		
			}
			else if(attrib == Attribute.bTimeLeft)
			{
				if(val)
					return (float)AT.THRESH_B_TIME_LEFT+1;
				return (float)AT.THRESH_B_TIME_LEFT-1;		
			}
			else if(attrib == Attribute.bHasFood)
			{
				if(val)
					return (float)AT.THRESH_B_HAS_FOOD+1;
				return (float)AT.THRESH_B_HAS_FOOD-1;		
			}
			else
			{
				return -1;
			}
		}
		
		//classifys a float value as a bool according to threshholds
		public bool valueForAttribute(Attribute attrib) 
		{
			if(attrib == Attribute.bCloseToGoal)
			{
				if(distanceToGoal > (float)AT.THRESH_B_CLOSE_TO_GOAL)
					return false;
				return true;		
			}
			else if(attrib == Attribute.bCloseToFood)
			{
				if(distanceToFood > (float)AT.THRESH_B_CLOSE_TO_FOOD)
					return false;
				return true;
			}
			else if(attrib == Attribute.bCloseToHerder)
			{
				if(distanceToHerder > (float)AT.THRESH_B_CLOSE_TO_HERDER)
					return false;
				return true;
			}
			else if(attrib == Attribute.bTimeLeft)
			{
				if(gameTimeLeft < (float)AT.THRESH_B_TIME_LEFT)
					return false;
				return true;
			}
			else //(attrib == Attribute.FoodLevel)
			{
				if(foodLevel < (float)AT.THRESH_B_HAS_FOOD)
					return false;
				return true;
			}
		}
		
		public float floatValueForAttribute(Attribute attrib) 
		{
			if(attrib == Attribute.bCloseToGoal)
			{
				return distanceToGoal;
			}
			else if(attrib == Attribute.bCloseToFood)
			{
				return distanceToFood;
			}
			else if(attrib == Attribute.bCloseToHerder)
			{
				return distanceToHerder;
			}
			else if(attrib == Attribute.bTimeLeft)
			{
				return gameTimeLeft;
			}
			else //(attrib == Attribute.FoodLevel)
			{
				return foodLevel;
			}
		}
		
		public float CurrentScore()
		{
			float score = 0;
			
			//provide score for distance to herder
			if(distanceToHerder > (float)AT.S_DIST_FROM_HERDER_GOOD)
				score += 6;
			else if(distanceToHerder < (float)AT.S_DIST_FROM_HERDER_BAD)
				score += 3;
			else
				score += 0;

			//provide score for distance to goal			
			if(distanceToGoal > (float)AT.S_DIST_FROM_GOAL_GOOD)
				score += 5;
			else if(distanceToGoal < (float)AT.S_DIST_FROM_GOAL_BAD)
				score += 3;
			else
				score += 1;
			
			//provide score for health level
			if(foodLevel > (float)AT.S_FOOD_GOOD)
				score += 4;
			else if(foodLevel < (float)AT.S_FOOD_BAD)
				score += 3;
			else
				score += 2;

			return score;
		}
	}	
}

